
package com.elong.common.dao;


import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;

import org.bson.BSON;
import org.bson.types.BasicBSONList;
import org.bson.types.ObjectId;

import com.alibaba.fastjson.JSON;
import com.elong.common.entity.Station;
import com.elong.common.util.PropUtil;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;




public class MongoDBUtil {
    
    //host name
    private static final String HOST = PropUtil.getPropValue("mdbc.host");
    
    //db name
    private static final String dbName = PropUtil.getPropValue("mdbc.database");
    
    //port
    private static final int PORT = Integer.valueOf(PropUtil.getPropValue("mdbc.port"));
    
    //mongo 实例
    private static MongoClient mongo;
    
    //private static MongoClient defaultClient;
    
    //private static MongoClient portClient;
    
    //replica set,  with auto-discovery of the primary, supply a seed list of members
    //private static MongoClient replicaClient;
    
    //db 实例
    private static DB db;
    
    //collectionName
    //private String collectionName;
    
    //集合
    private DBCollection collection;
    
    //初始化
    static{
        try {
            MongoClientOptions options = new MongoClientOptions.Builder()
                                    .autoConnectRetry(true)
                                    .connectionsPerHost(100)
                                    .connectTimeout(20000)
                                    .maxAutoConnectRetryTime(3)
                                    .build();
            mongo = new MongoClient(new ServerAddress(HOST, PORT), options);
            //defaultClient = new MongoClient(HOST);
            //portClient = new MongoClient(HOST, 27017);
/*            replicaClient = new MongoClient(
                    Arrays.asList(new ServerAddress("localhost", 27017),
                            new ServerAddress("localhost", 27018),
                            new ServerAddress("localhost", 27019)));*/
            db = mongo.getDB(dbName);
            //设置用户名密码
            String username = PropUtil.getPropValue("mdbc.username");
            String password = PropUtil.getPropValue("mdbc.password");
            
            boolean loginSuccess = db.authenticate(username, password.toCharArray());
            if(!loginSuccess){
                throw new Exception("登陆数据库授权失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    //初始化
    public MongoDBUtil(String collectionName){
        collection = getCollection(collectionName);
    }
    
    
    /**
     * @Description: 判断集合是否存在
     * @param collectName
     * @return
     * @throws
     */
    public static boolean CollectionExists(String collectName){
        return db.collectionExists(collectName);
    }
    
    /** 获取集合 **/
    public static DBCollection getCollection(String collectName){
        return db.getCollection(collectName);
    }
    
    /** 获取所有集合类 **/
    public static Set<String> getAllCollection(){
        return db.getCollectionNames();
    }
    
    /**
     * @Description: 创建集合
     * @param collectName
     * @param options
     * @throws
     */
    public static void createCollection(String collectName, DBObject options){
        db.createCollection(collectName, options);
    }
    
    /** 删除集合**/
    public void dropCollection(){
        if(collection != null)
            collection.drop();
    }
    
    /**
     * @Description: 根据条件获得记录
     * @param map
     * @return
     * @throws
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private  DBObject getMapped(Map<String, Object> map){
        DBObject dbObject = new BasicDBObject();
        Iterator<Entry<String, Object>> iter = map.entrySet().iterator();
        while(iter.hasNext()){
            Entry<String, Object> entry = iter.next();
            Object value = entry.getValue();
            String key = entry.getKey();
            //说明是复合查询
            if(key.startsWith("$") && value instanceof Map){
                BasicBSONList basicBSONList = new BasicBSONList();
                Map<String, Object> conditionMap = (Map<String, Object>) value;
                Set<String> keys = conditionMap.keySet();
                for(String k : keys){
                    Object conditionValue = conditionMap.get(k);
                    if(conditionValue instanceof Collection){
                        conditionValue = convertToArray(conditionMap);
                    }
                    DBObject object2 = new BasicDBObject(k, conditionValue);
                    basicBSONList.add(object2);
                }
                value = basicBSONList;
            }else if( value instanceof Collection){
                value = convertToArray(value);
            }else if(!key.startsWith("$") && value instanceof Map){
                value = getMapped((Map)value);
            }
            dbObject.put(key, value);
        }
        return dbObject;
    }
    
    //object 转化为 array
    @SuppressWarnings("rawtypes")
    public Object[] convertToArray(Object value){
        Object[] values = ((Collection)value).toArray();
        return values;
    }
    
    /**
     * <p>查询记录</p>
     * @param dbObject
     * @param cursor
     * @throws
     */
    public List<DBObject> find(DBObject dbObject, final CursorObject cursor){
        CursorPreparer cursorPreparer = new CursorPreparer() {
            
            @Override
            public DBCursor prepare(DBCursor dbcursor) {
                if(cursor == null)
                    return dbcursor;
                if(cursor.getLimit() <= 0 && cursor.getSkip() <= 0
                        && cursor.getSortObject() == null)
                    return dbcursor;
                DBCursor cursorToUse = dbcursor;
                if(cursor.getSkip() > 0){
                    cursorToUse = cursorToUse.skip(cursor.getSkip());
                }
                if(cursor.getLimit() > 0){
                    cursorToUse = cursorToUse.limit(cursor.getLimit());
                }
                if(cursor.getSortObject() != null){
                    cursorToUse =cursorToUse.sort(cursor.getSortObject());
                }
                return cursorToUse;
            }
        };
        return find(dbObject, cursor, cursorPreparer);
    }
    
    //获取记录
    public List<DBObject> find(DBObject dbObject, CursorObject cursor,
                        CursorPreparer cursorPrepare){
        DBCursor dbCursor = collection.find(dbObject);
        if(cursorPrepare != null){
            dbCursor = cursorPrepare.prepare(dbCursor);
        }
        List<DBObject> objs = new ArrayList<>();
        Iterator<DBObject> iterator = dbCursor.iterator();
        while(iterator.hasNext()){
            objs.add(iterator.next());
        }
        dbCursor.close();
        return objs;
    }
    
    /**
     * @Description: 根据主键查询一条记录
     * @param id
     * @param collectName
     * @throws
     */
    public DBObject findById(String id){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("_id", new ObjectId(id));
        return findOne(map);
    }
    
    /**
     * @Description: 查询单个
     * @param args
     * @throws
     */
    public DBObject findOne(Map<String, Object> map){
        DBObject dbObject = getMapped(map);
        DBObject object = collection.findOne(dbObject);
        return object;
    }
    
    /**
     * @Description: 根据查询条件获得 结果
     * @param conditonMap
     * @return
     * @throws
     */
    /** 查找记录 **/
    public List<DBObject> findByCondition(Map<String, Object> conditionMap, CursorObject cursor){
/*        DBObject queryObject = getMapped(conditionMap);
        DBCursor cursor = collection.find(queryObject);
        List<DBObject> lists = new ArrayList<>();
        while(cursor.hasNext()){
            lists.add(cursor.next());
        }
        cursor.close();
        return lists;*/
        DBObject queryObj = getMapped(conditionMap);
        return find(queryObj, cursor);
    }
    
    public List<DBObject> findByFuzzy(String key, String content, CursorObject cursor){
        DBObject dbo = new BasicDBObject();
        Pattern pattern = Pattern.compile("^.*" + content + ".*$", Pattern.CASE_INSENSITIVE);
        dbo.put(key, pattern);
        return find(dbo, cursor);
    }
    
    
    //查询所有记录
    public List<DBObject> findAll(){
        DBCursor cursor = collection.find();
        List<DBObject> lists = new ArrayList<>();
        while(cursor.hasNext()){
            lists.add(cursor.next());
        }
        cursor.close();
        return lists;
    }
    
    
    /**
     * @Description: 获取记录总数
     * @param map
     * @param collectionName
     * @return
     * @throws
     */
    public long count(Map<String, Object> map){
        DBObject dbObject = getMapped(map);
        return collection.count(dbObject);
    }
    
    /**
     * @Description: 插入记录
     * @param args
     * @throws
     */
    public boolean insertDoc(Map<String, Object> record){
        Iterator<Entry<String, Object>> iter = record.entrySet().iterator();
        BasicDBObject doc = new BasicDBObject();
        while(iter.hasNext()){
            Map.Entry<String, Object> entry = iter.next();
            doc.append(entry.getKey(), entry.getValue());
        }
        WriteResult result = collection.insert(doc, WriteConcern.SAFE);
        if("null".equals(result.getError()))
            return true;
        else {
            return false;
        }
    }
    
    /**
     * @Description: 插入记录
     * @param args
     * @throws
     */
    public boolean insertJsonDoc(String jsonStr){
        DBObject dbObject =(DBObject)JSON.parse(jsonStr);
        WriteResult result = collection.insert(dbObject, WriteConcern.SAFE);
        if("null".equals(result.getError())){
            return true;
        }else {
            return false;
        }
    }
    
    //删除记录
    public boolean deleteRecord(String key, String value){
        DBObject doc = new BasicDBObject(key, value);
        collection.remove(doc, WriteConcern.SAFE);
        return true;
    }
    
    /** 更新记录 **/
    public boolean update(Map<String, Object> condMap, Map<String, Object> updateMap){
        DBObject condObj = getMapped(condMap);
        DBObject updateValue = new BasicDBObject();
        Set<String> keys = updateMap.keySet();
        for(String key : keys){
            updateValue.put(key, updateMap.get(key));
        }
        DBObject updateObj = new BasicDBObject("$set", updateValue);
        //第三个参数： 如果没有符合条件的记录，则插入； 第四个参数：是否更新多条记录
        collection.update(condObj, updateObj, false, true, WriteConcern.SAFE);
        return true;
    }
    
    /**
     * <p>删除集合</p>
     * @param args
     * @throws
     */
    public static void dropCollection(String collectionName){
        DBCollection conn = getCollection(collectionName);
        conn.drop();
    }
    
    
    public static void main(String[] args) {
        System.out.println(MongoDBUtil.getAllCollection());
        MongoDBUtil util = new MongoDBUtil("station");
        dropCollection("station");
        Map<String, Object> record = new HashMap<>();
        record.put("stationName", "beijingnan");
        record.put("stationCode", "BJN");
        util.insertDoc(record);
        
        Map<String, Object> inMap = new HashMap<>();
        inMap.put("$in", new String[]{"beijing","nanjing1"});
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("stationName", "beijing");

        List<DBObject> objs = util.findAll();
        for(DBObject obj : objs){
            Station sta = JSON.parseObject(obj.toString(), Station.class);
            System.out.println(sta.get_id());
            System.out.println(obj);
        }
    }
}
